import datetime
import logging
import time
from typing import List

import pandas as pd
from fastapi.routing import APIRouter
from starlette.status import HTTP_404_NOT_FOUND
from tortoise import transactions
from tortoise.contrib.pydantic import pydantic_model_creator
from uvicorn.config import LOGGING_CONFIG

from ModelPydantic import KumquatIn, OrderIn, OrderFilter
from models import Order, Customer, Kumquat
import copy

from toolkit import convert_date

order = APIRouter()
LOGGING_CONFIG["formatters"]["default"]["fmt"] = "%(asctime)s - %(levelprefix)s %(message)s"
orderFieldList = ["customer__name", "customer__address",
                  "customer__phoneNumber", "customer__presenter",
                  "kumquat__name", "kumquat__style", "kumquat__price", "kumquat__original_price",
                  "book_date", "on_sold", "quantity", "price", "status"]


@order.get("/schema", tags=["Get Order Schema"], summary="Well it's not readable...",
           description="Schema Test",
           response_description="Return the Order Schema")
async def get_order_schema():
    orderPydantic = pydantic_model_creator(Order)
    return {'message': orderPydantic.model_json_schema()}


@order.get("/all", tags=["Get All Orders"], summary="List All Orders",
           description="Fetches a list of all order records.",
           response_description="A list of all order is returned.")
async def get_all_orders():
    orders = await Order.all().values(*orderFieldList)
    return {'message': 'OK', 'data': orders}, 200


@order.get("/<order_id>", tags=["Get Single Order"], summary="Find Order by ID",
           description="Retrieves a single Order record based on the provided Order ID.",
           response_description="The matching Order record is returned.")
async def get_order_id(order_id):
    orderById = await Order.filter(id=order_id).values(*orderFieldList)
    return {"message": 'OK', 'data': orderById}, 200


@order.post("/filter", tags=["Get Order by multiple filters"])
async def get_order_by_filter(orderFilter: OrderFilter):
    # 初始化过滤条件字典
    orderDBFilter = {
        'customer__name': orderFilter.customer_name,
        'customer__presenter': orderFilter.customer_presenter,
        'kumquat__name': orderFilter.kumquat_name,
        'kumquat__style': orderFilter.kumquat_style,
        'status': orderFilter.status,
        'note': orderFilter.note,
    }
    # 移除值为None的键，避免无效过滤
    orderDBFilter = {k: v for k, v in orderDBFilter.items() if len(v) > 0}
    print(orderDBFilter)
    # 解析日期范围，添加异常处理
    try:
        startDateObj = datetime.datetime.strptime(orderFilter.start_date,
                                                  "%Y-%m-%d") if orderFilter.start_date else None
        endDateObj = datetime.datetime.strptime(orderFilter.end_date, "%Y-%m-%d") if orderFilter.end_date else None
        # 确保开始日期小于等于结束日期
        if startDateObj and endDateObj and startDateObj > endDateObj:
            raise ValueError("Start date must be less than or equal to end date.")
    except ValueError as e:
        return {"message": f"Invalid date format: {e}"}, 400

    # 只有当起始和结束日期都有值时，才添加时间范围过滤
    if startDateObj and endDateObj:
        ordersRange = await Order.filter(book_date__gte=startDateObj, book_date__lte=endDateObj,
                                         **orderDBFilter).values(*orderFieldList)
    else:
        ordersRange = await Order.filter(**orderDBFilter).values(*orderFieldList)

    return {"message": 'OK', 'data': ordersRange}, 200


@order.post("/", tags=['Add an order to record'])
async def new_order(orderIn: OrderIn):
    custFilter = {}
    if orderIn.customer_name != 'None':
        custFilter['name'] = orderIn.customer_name
    if orderIn.customer_addr != 'None':
        custFilter['address'] = orderIn.customer_addr
    if orderIn.customer_phoneNumber != 'None':
        custFilter['phoneNumber'] = orderIn.customer_phoneNumber
    custFilter['presenter'] = orderIn.customer_presenter
    customerOrdered = await Customer.filter(**custFilter).first()
    if customerOrdered:
        logging.info("ADD ORDER: FIND CUSTOMER")
    else:
        print("NEW CUSTOMER, WILL ADD IT TO DB")
        await Customer(**custFilter).save()
        customerOrdered = await Customer.filter(**custFilter).first()
    print(customerOrdered.id)
    kumquatFilter = {'note': 'CURRENT'}
    if orderIn.kumquat_name != 'None':
        kumquatFilter['name'] = orderIn.kumquat_name
    if orderIn.kumquat_style != 'None':
        kumquatFilter['style'] = orderIn.kumquat_style
    kumquatOrdered = await Kumquat.filter(**kumquatFilter).first()
    if kumquatOrdered:
        logging.info(f"ADD ORDER: FIND THE KUMQUAT TO PURCHASE: {kumquatOrdered}")
    else:
        logging.error("ADD ORDER: NO SUCH KUMQUAT, ADD ORDER FAILED!")
        return {"message": "Failed! No such kumquat. Please add it firstly."}, 404

    newOrder = Order(customer=customerOrdered, kumquat=kumquatOrdered, quantity=orderIn.quantity,
                     on_sold=orderIn.on_sold, status=orderIn.status, note=orderIn.note,
                     order_delivery_code=orderIn.order_delivery_code, book_date=convert_date(orderIn.book_date),
                     price=0)
    newOrder.get_price()
    await newOrder.save()
    return {"message": 'OK'}, 201


@order.post('/all', tags=['Bulk insert orders'],
            description="Bulk create Order records based on the provided information, but please make sure that "
                        "customers and kumquats does exist.")
async def bulk_insert_orders(ordersIn: List[OrderIn]):
    orderToCreate = []
    logging.info(f"order: {ordersIn[0]}")
    for orderIn in ordersIn:
        custFilter = {}
        kumquatFilter = {}
        if orderIn.customer_name != 'None':
            custFilter['name'] = orderIn.customer_name
        if orderIn.customer_addr != 'None':
            custFilter['address'] = orderIn.customer_addr
        if orderIn.customer_phoneNumber != 'None':
            custFilter['phoneNumber'] = orderIn.customer_phoneNumber
        custFilter['presenter'] = orderIn.customer_presenter
        customerOrdered = await Customer.filter(**custFilter).first()
        if customerOrdered:
            logging.info("ADD ORDER: FOUND CUSTOMER")
        else:
            logging.error("NO SUCH CUSTOMER: BULK CREATE ORDER FAILED.")
            return {"message": f"Failed! No such customer {custFilter}. Please add it firstly."}, 404

        if orderIn.kumquat_name != 'None':
            kumquatFilter['name'] = orderIn.kumquat_name
        if orderIn.kumquat_style != 'None':
            kumquatFilter['style'] = orderIn.kumquat_style
        kumquatFilter['note'] = 'CURRENT'
        kumquatOrdered = await Kumquat.filter(**kumquatFilter).first()
        if kumquatOrdered:
            logging.info(f"ADD ORDER: FIND THE KUMQUAT TO PURCHASE: {kumquatOrdered}")
        else:
            logging.error("ADD ORDER: NO SUCH KUMQUAT, ADD ORDER FAILED!")
            return {
                "message": f"Failed! No such kumquat {orderIn.kumquat_name}, {orderIn.kumquat_style}. Please add it firstly."}, 404
        newOrder = Order(customer=customerOrdered, kumquat=kumquatOrdered, quantity=orderIn.quantity,
                         on_sold=orderIn.on_sold, status=orderIn.status, note=orderIn.note,
                         order_delivery_code=orderIn.order_delivery_code, price=0, book_date=orderIn.book_date)
        newOrder.get_price()
        orderToCreate.append(newOrder)
        # logging.info(f"ADD ORDER {newOrder}")
    async with transactions.in_transaction():  # make sure atomics
        await Order.bulk_create(orderToCreate)
    return {"message": 'OK'}, 201


# @order.get('/report', tags=['View orders report'])
# async def view_orders_report(start_date: str, end_date: str):
#     startDateObj = datetime.datetime.strptime(start_date, "%Y-%m-%d")
#     endDateObj = datetime.datetime.strptime(end_date, "%Y-%m-%d")
#     requestOrdersRaw = await Order.filter(book_date__gte=startDateObj, book_date__lte=endDateObj) \
#         .all().values(*orderFieldList)
#     requestOrdersDF = pd.DataFrame(list(requestOrdersRaw))
#
#     # Build report, group the kumquat and presenter's info.
#
#     reportData = {
#                     "amount": requestOrdersDF['price'].sum(),
#                     # "orders": requestOrdersDF.to_dict(orient='records')
#                  }
#     return {"message": 'OK', 'data': reportData}, 200
